from flask import Blueprint, request, g, session, jsonify
from Logger import logger
from utils import MyResponse, handle_exception, handle_success
import jwt
import datetime
import time
import bcrypt
from db_handler import db_handler

user = Blueprint('user', __name__)
secret_key = 'ckj.1029'  # 修改为与 auth.py 一致的密钥


# 获取当前时间的毫秒级时间戳
def get_current_timestamp_ms():
    return int(datetime.datetime.now().timestamp() * 1000)


# 生成新的会话ID
def generate_new_session(user_info):
    session.clear()
    session.permanent = True
    session['userid'] = user_info['id']
    session['loginname'] = user_info['login_name']
    session['client_ip'] = request.headers.get('X-Real-IP')
    logger.info("为用户: %s 生成新会话ID", session['loginname'])


@user.route('/register', methods=['POST'])
def register():
    try:
        params = request.json
        # 参数验证
        required_fields = ['loginname', 'username', 'password', 'department']
        if not all(field in params for field in required_fields):
            return handle_exception({"msg": "缺少必要的参��"}, "error")

        loginname = params['loginname']
        username = params['username']
        password = params['password']
        department = params['department']

        # 检查用户名是否存在
        check_query = "SELECT COUNT(*) as countNum FROM User WHERE login_name = %s"
        existing_count = db_handler.execute_query(check_query, (loginname,))[0]['countNum']

        if existing_count > 0:
            return handle_exception({"msg": "该用户名已被占用"}, "该用户名已被占用")

        # 密码加密
        hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())

        # 插入用户信息
        insert_query = "INSERT INTO User (login_name, user_name, password, department) VALUES (%s, %s, %s, %s)"
        insert_params = (loginname, username, hashed_password, department)
        result = db_handler.insert(insert_query, insert_params)

        if result is None:
            return handle_exception({"msg": "数据库操作失败"}, "error")

        return handle_success({"msg": "用户新增成功"}, "success")
    except KeyError as e:
        return handle_exception({"msg": f"缺少参数：{str(e)}"}, "error")
    except Exception as err:  # 捕获异常
        return handle_exception(err, "程序异常")


@user.route('/changpwd', methods=['POST'])
def change_password():
    try:
        params = request.json
        # 参数验证
        required_fields = ['userId', 'oldPassword', 'newPassword']
        if not all(field in params for field in required_fields):
            return handle_exception({"msg": "缺少必要的参数"}, "error")

        old_password = params['oldPassword']
        new_password = params['newPassword']
        user_id=params['userId']
        # 验证旧密码
        query = "SELECT password FROM User WHERE id = %s"
        user = db_handler.execute_query(query, (user_id,))
        if not user or not user[0]:
            return handle_exception({"msg": "用户不存在或密码错误"}, "用户不存在或密码错误")

        # 检查旧密码是否正确
        stored_password = user[0]['password']
        if not bcrypt.checkpw(old_password.encode('utf-8'), stored_password.encode('utf-8')):
            return handle_exception({"msg": "旧密码不正确"}, "旧密码不正确")

        # 更新密码
        hashed_password = bcrypt.hashpw(new_password.encode('utf-8'), bcrypt.gensalt())
        update_query = "UPDATE User SET password = %s WHERE id = %s"
        update_params = (hashed_password, user_id)
        result = db_handler.update(update_query, update_params)

        if result is None or result == 0:
            return handle_exception({"msg": "密码更新失败"}, "error")

        return handle_success({"msg": "密码更新成功"}, "success")
    except KeyError as e:
        return handle_exception({"msg": f"缺少参数：{str(e)}"}, "error")
    except Exception as err:  # 捕获异常
        return handle_exception(err, "程序异常")


@user.route('/login', methods=['POST'])
def login():
    try:
        params = request.json
        username = params['username']
        password = params['password']

        # 查询用户信息
        query = "SELECT * FROM User WHERE login_name = %s"
        user = db_handler.execute_query(query, (username,))

        if not user:
            return handle_exception({"err": "用户不存在"}, "用户不存在")

        # 检查用户是否启用
        if user[0]['enable'] != 1:
            return handle_exception({"err": "账户已禁用"}, "账户已禁用，请联系性能实验室")

        # 检查是否存在有效的会话
        current_time = get_current_timestamp_ms()
        session_check_query = """
            SELECT * FROM UserSessions 
            WHERE user_id = %s AND expires_at > %s AND session_token != 'expired'
        """
        active_session = db_handler.execute_query(session_check_query, (user[0]['id'], current_time))

        client_ip = request.headers.get('X-Real-IP')

        # 如果已有有效会话，拒绝新的登录
        if active_session:
            existing_ip = active_session[0]['client_ip']
            if existing_ip != client_ip:
                return handle_exception({"msg": f"用户已在其他终端（IP: {existing_ip}）登录"}, f"用户已在其他终端（IP: {existing_ip}）登录")
            else:
                # 同一终端，更新session_token为expired
                update_query = "UPDATE UserSessions SET session_token = %s, expires_at = %s WHERE client_ip = %s and session_token<>''"
                db_handler.update(update_query, ('expired', current_time, client_ip))

        # 验证密码
        if not bcrypt.checkpw(password.encode('utf-8'), user[0]['password'].encode('utf-8')):
            return handle_exception({"err": "密码错误"}, "密码错误")

        # 设置 Token 过期时间
        expires = get_current_timestamp_ms() + (1 * 60 * 60 * 1000)  # 1小时

        # 生成 Token
        access_token = jwt.encode(
            {'username': username, 'userid': user[0]['id'], 'roles': ['admin'] if user[0]['is_admin'] else ['common'], 'exp': expires},
            secret_key,
            algorithm='HS256'
        )
        refresh_token = jwt.encode(
            {'username': username, 'userid': user[0]['id'], 'roles': ['admin'] if user[0]['is_admin'] else ['common'], 'create': get_current_timestamp_ms()},
            secret_key,
            algorithm='HS256'
        )

        # 创建新会话
        insert_query = "INSERT INTO UserSessions (user_id, session_token, client_ip, expires_at) VALUES (%s, %s, %s, %s)"
        db_handler.insert(insert_query, (user[0]['id'], access_token, client_ip, expires))

        # 更新用户的最后登录时间
        new_session = db_handler.execute_query(
            'SELECT MAX(id) AS id FROM UserSessions WHERE user_id = %s', (user[0]['id'],)
        )
        if new_session and new_session[0]['id']:
            update_last_login_query = "UPDATE UserSessions SET last_login = %s WHERE id = %s"
            last_login_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
            db_handler.update(update_last_login_query, (last_login_time, new_session[0]['id']))

        else:
            return handle_exception({"msg": "创建会话失败"}, "创建会话失败")

        # 获取用户有权限的项目列表
        project_query = "SELECT project_name FROM project WHERE user_id = %s OR (SELECT is_admin FROM User WHERE id = %s) = 1"
        project_list = db_handler.execute_query(project_query, (user[0]['id'], user[0]['id']))
        project_names = [project['project_name'] for project in project_list] if project_list else []



        user_data = {
            'username': username,
            'userid': user[0]['id'],
            'roles': ["admin"] if user[0]['is_admin'] else ["common"],
            'accessToken': access_token,
            'refreshToken': refresh_token,
            'expires': expires
        }

        generate_new_session(user[0])
        # 将项目列表放入会话中
        session['projects'] = project_names
        logger.info("用户: %s 登录成功", username)
        return handle_success(user_data, "success")
    except KeyError as e:
        return handle_exception({"msg": f"缺少参数：{str(e)}"}, "error")
    except Exception as err:  # 捕获异常
        logger.error(f"登录时出错: {err}")
        return handle_exception(err, "程序异常")


@user.route('/refreshToken', methods=['POST'])
def refresh():
    try:
        params = request.json
        token = params['refreshToken']
        now = int(datetime.datetime.now().timestamp() * 1000)

        # 验证刷新 Token
        payload = jwt.decode(token, secret_key, algorithms=['HS256'])


        # refreshToken过期时间为2小时
        if now - payload['create'] <= 2 * 60 * 60 * 1000:
            username = payload['username']
            roles = payload['roles']

            # 设置 Token 过期时间 1小时
            expires = now + (1 * 60 * 60 * 1000)
            access_token = jwt.encode(
                {'username': username, 'userid': payload['userid'], 'roles': roles, 'exp': expires},
                secret_key,
                algorithm='HS256'
            )
            refresh_token = jwt.encode(
                {'username': username, 'userid': payload['userid'], 'roles': roles, 'create': now},
                secret_key,
                algorithm='HS256'
            )

            data = {
                "accessToken": access_token,
                "refreshToken": refresh_token,
                "expires": expires
            }

            # 更新数据库中的 session_token 和 expires_at
            user_id = session.get('userid')
            if user_id:
                # 获取最后登录的一条记录
                latest_session_query = "SELECT id FROM UserSessions WHERE user_id = %s ORDER BY last_login DESC LIMIT 1"
                latest_session = db_handler.execute_query(latest_session_query, (user_id,))
                if latest_session:
                    latest_session_id = latest_session[0]['id']
                    update_query = "UPDATE UserSessions SET session_token = %s, expires_at = %s WHERE id = %s"
                    db_handler.update(update_query, (refresh_token, expires, latest_session_id))
                else:
                    return handle_exception({"msg": "未找到用户会话"}, "error")
            else:
                return handle_exception({"msg": "未找到用户会话"}, "error")
        else:
            return MyResponse("Token过期，请重新登录", False, "Token过期，请重新登录").post()

    except KeyError as e:
        return handle_exception({"msg": f"缺少参数：{str(e)}"}, "error")
    except jwt.ExpiredSignatureError:
        return handle_exception({"msg": "Token已过期"}, "error")
    except jwt.DecodeError:
        return handle_exception({"msg": "Token格式错误"}, "error")
    except Exception as err:  # 捕获异常
        return handle_exception(err, "程序异常")
    else:
        logger.info("用户 %s 刷新了 Token", username)
        return handle_success(data, "success")


@user.route('/getAsyncRoutes')
def get_async_routes():
    res = MyResponse([], True, "success").post()
    return res


@user.route('/logout', methods=['POST'])
def logout():
    try:
        # 假设用户ID存储在session中
        username = session.get('loginname')
        user_id = session.get('userid')
        if not user_id:
            return handle_exception({"err": "未找到用户会话"}, "未找到用户会话")

        # 更新用户会话记录，设置 token 过期
        new_session = db_handler.execute_query(
            'SELECT MAX(id) AS id FROM UserSessions WHERE user_id = %s', (user_id,)
        )
        if new_session and new_session[0]['id']:
            update_query = "UPDATE UserSessions SET session_token = %s, expires_at = %s WHERE id = %s"
            expired_token = 'expired'
            expired_time = get_current_timestamp_ms()  # 当前时间戳（毫秒）
            update_result = db_handler.update(update_query, (expired_token, expired_time, new_session[0]['id']))
            if update_result:
                logger.info("用户 %s 退出系统，已将 session_token 设置为 'expired'。", username)
            else:
                logger.error("用户 %s 退出系统时，更新 session_token 失败。", username)
                return handle_exception({"err": "更新会话失败"}, "退出登录失败")
        else:
            return handle_exception({"err": "未找到用户会话"}, "未找到用户会话")

        session.clear()
        logger.info("用户 %s 退出系统。", username)
    except Exception as err:
        logger.error(f"退出登录时出错: {err}")
        return handle_exception(err, "程序异常")
    else:
        return handle_success({}, "退出登录成功")


def invalidate_all_sessions():
    try:
        update_query = "UPDATE UserSessions SET session_token = %s, expires_at = %s WHERE session_token != 'expired'"
        expired_token = 'expired'
        current_time = int(datetime.datetime.now().timestamp() * 1000)
        db_handler.update(update_query, (expired_token, current_time))
        logger.info("所有用户会话已失效。")
    except Exception as e:
        logger.error(f"失效用户会话时出错: {e}")